package com.bb.blog.security.resource;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bb.blog.web.exception.ServerException;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;

import java.net.URL;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;

import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.*;

/**
 * 使用响应值中的auth作为权限字段 或者进行一个权限的映射
 */

@RequiredArgsConstructor
public class BbOpaqueTokenIntrospector implements OpaqueTokenIntrospector {

    private final OpaqueIntrospectorClient opaqueIntrospectorClient;


    @Override
    public OAuth2AuthenticatedPrincipal introspect(String token) {
        JSONObject response = opaqueIntrospectorClient.introspect(token);
        if (response == null) {
            throw new  OAuth2IntrospectionException("认证服务器异常");
        }

        if (!response.getBoolean("active")) {
            throw new BadOpaqueTokenException("Provided token isn't active");
        }
        response.computeIfPresent(ISSUED_AT, (k, v) -> Instant.ofEpochMilli(response.getLong(k)));
        response.computeIfPresent(EXPIRES_AT, (k, v) -> Instant.ofEpochMilli(response.getLong(k)));
        // relying solely on the authorization server to validate this token (not checking 'exp', for example)


        return convertClaimsSet(response);
    }

    private OAuth2AuthenticatedPrincipal convertClaimsSet(JSONObject jsonObject) {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        if (jsonObject.get("auth") != null) {
            JSONArray auths = jsonObject.getJSONArray("auth");
            for (int i = 0; i < auths.size(); i++) {
                String auth = auths.getString(i);
                authorities.add(new SimpleGrantedAuthority(auth));
            }
        }

        return new DefaultOAuth2AuthenticatedPrincipal(jsonObject, authorities);
    }

    private URL issuer(String uri) {
        try {
            return new URL(uri);
        } catch (Exception ex) {
            throw new OAuth2IntrospectionException("Invalid " + ISSUER + " value: " + uri);
        }
    }

}
